// Includes
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <limits.h>

#include <iostream>
#include <string>

#include <ctime>
#include <cstdlib>

//Incluyo la clase global.cpp  que contiene las variables y funciones globales
#include "../utils/global.cpp"

//Incluyo la clase mt.cpp para valores aleatorios
#include "../utils/mt.cpp"

using namespace std;


/****************** Representacion Permutacion ********************/

/******************* Declaracion de Funciones del Host *************************/
void representacionPermutacion();

/******************* Declaracion de Funciones Global del  ********************/
 void inicializarPoblacionPermutacion(int* poblacion, int* fitnessActual, MersenneTwister *mt, int cantCromosomasPoblacion);
 void mainKernelPermutacion(int* poblacionActual, int* nuevaPoblacion, int* fitnessActual, int* nuevoFitness, int* individuosAMigrar, MersenneTwister *mt, int nroPoblacion, int posActual);

/******************* Declaracion de Funciones internas del  *****************/
 int seleccionPermutacion(int* vectorFitness, MersenneTwister *mt, int ejecutarFuncion, int indiceMejor, int nroPoblacion, int posActual);
 int seleccionPorTorneoPermutacion(int* vectorFitness, MersenneTwister *mt, int nroPoblacion, int posActual);
 int seleccionPorRangoPermutacion(int* vectorFitness, int indiceMejor, int nroPoblacion, int posActual);
 int seleccionElitistaPermutacion(int* vectorFitness, int indiceMejor, int nroPoblacion, int posActual);

 void cruzamientoRepresentacionPermutacion(int* poblacionActual, int* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, int probabilidad, MersenneTwister *mt, int ejecutarFuncion, int nroPoblacion, int posActual);
 void cruzamientoCromosomaPMX(int* poblacionActual, int* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, int probabilidad, MersenneTwister *mt, int nroPoblacion, int posActual);
 void cruzamientoCromosomaOX(int* poblacionActual, int* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, int probabilidad, MersenneTwister *mt, int nroPoblacion, int posActual);
 void cruzamientoCromosomaCX(int* poblacionActual, int* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, int probabilidad,MersenneTwister *mt, int nroPoblacion, int posActual);

 void mutacionPermutacion(int* poblacion, int probabilidad, MersenneTwister *mt, int ejecutarFuncion, int nroPoblacion, int posActual);
 void mutacionPorIntercambio(int* poblacion, int probabilidad, MersenneTwister *mt, int nroPoblacion, int posActual);
 void mutacionPorInsercionSimple(int* poblacion, int probabilidad, MersenneTwister *mt, int nroPoblacion, int posActual);
 void mutacionPorInversionIVM(int* poblacion, int probabilidad, MersenneTwister *mt, int nroPoblacion, int posActual);
 void mutacionPorMezcla(int* poblacion, int probabilidad, MersenneTwister *mt, int nroPoblacion, int posActual);

 void asignarFitnessPermutacion(int* poblacion, int* vectorFitness, int nroPoblacion, int posActual);
 int calcularFitnessPermutacion(int* poblacion, int posicion);

/******************* Implementacion de Funciones del  *****************/


 void inicializarPoblacionPermutacion(int* poblacion, int* fitnessActual, MersenneTwister *mt, int cantCromosomasPoblacion){
	//Obtengo posicion a escribir.
	int posicionCromosoma = 0;
	int posicionFitness = 0;

	//inicializo la poblacion en -1
	for(int i = 0; i<cantGenesEnCromosoma * cantidadPoblaciones * cantCromosomasPoblacion; i++){
		poblacion[posicionCromosoma+i] = -1;
	}


	for(int i = 0; i< cantidadPoblaciones * cantCromosomasPoblacion; i++){

		for(int j = 0; j<cantGenesEnCromosoma; j++){
			//Genero valor aleatorio.
			unsigned int r = (mt->genrand_int32()% cantGenesEnCromosoma);
			while(poblacion[posicionCromosoma + r] != -1){
				r = (r+1) % cantGenesEnCromosoma;
			}
			poblacion[posicionCromosoma+r] = j;
		}
		posicionCromosoma = posicionCromosoma + cantGenesEnCromosoma;
	}

	posicionCromosoma = 0;
	for(int i = 0; i< cantidadPoblaciones * cantCromosomasPoblacion; i++){
		fitnessActual[posicionFitness] = calcularFitnessPermutacion(poblacion, posicionCromosoma);
		posicionFitness++;
		posicionCromosoma = posicionCromosoma + cantGenesEnCromosoma;
	}
}



 void mainKernelPermutacion(int* poblacionActual, int* nuevaPoblacion, int* fitnessActual, int* nuevoFitness, int* individuosAMigrar, MersenneTwister *mt, int nroPoblacion, int posActual){
	//genero numero aleatorio entre 0 y cant individuos por poblacion
	int posicionCromosoma1 = seleccionPermutacion(fitnessActual, mt, tipoSeleccion, 1, nroPoblacion, posActual);
	int posicionCromosoma2 = seleccionPermutacion(fitnessActual, mt, tipoSeleccion, 2, nroPoblacion, posActual);
	cruzamientoRepresentacionPermutacion(poblacionActual, nuevaPoblacion, posicionCromosoma1, posicionCromosoma2, probabilidadCruzamiento, mt, tipoCruzamiento, nroPoblacion, posActual);
	mutacionPermutacion(nuevaPoblacion, probabilidadMutacion, mt, tipoMutacion, nroPoblacion, posActual);

	asignarFitnessPermutacion(nuevaPoblacion, nuevoFitness, nroPoblacion, posActual);

	//__syncthreads();
	//if (threadIdx.x == 0) {
	///	individosAMigrarRepresentacionPermutacion(nuevoFitness, nuevaPoblacion, individuosAMigrar);
	//}
}



/******************* Implementacion de Funciones de Migracion *****************/




/******************* Implementacion de Funciones de Selecccion *****************/


 int seleccionPermutacion(int* vectorFitness, MersenneTwister *mt, int ejecutarFuncion, int indiceMejor, int nroPoblacion, int posActual){
	int resultado = -1;
	if(ejecutarFuncion == 0) {
		resultado = seleccionElitistaPermutacion(vectorFitness, indiceMejor, nroPoblacion, posActual);
	}
	else{
		if(ejecutarFuncion == 1){
			resultado = seleccionPorTorneoPermutacion(vectorFitness, mt, nroPoblacion, posActual);
		}
		/*else {
			if(ejecutarFuncion == 2) {
				//seleccionElitistaPermutacion(vectorFitness, mt);
			}
		}*/
	}
	return resultado;
}


//Seleccion por torneo
//selecciona 2 individuos al azar y devuelve la posicion del mejor
 int seleccionPorTorneoPermutacion(int* vectorFitness, MersenneTwister *mt, int nroPoblacion, int posActual){
	printf("*** Seleccion por torneo ***\n");
	unsigned int r = mt->genrand_int32()% cantCromosomasPoblacion;
	int posicionFitnessAleatoria1 = nroPoblacion * cantCromosomasPoblacion + r;
	int posicionCromosomaAleatoria1 = nroPoblacion * cantCromosomasPoblacion * cantGenesEnCromosoma + r * cantGenesEnCromosoma;
	r = mt->genrand_int32()% cantCromosomasPoblacion;
	int posicionFitnessAleatoria2 = nroPoblacion * cantCromosomasPoblacion + r;
	int posicionCromosomaAleatoria2 = nroPoblacion * cantCromosomasPoblacion * cantGenesEnCromosoma + r * cantGenesEnCromosoma;
	if (vectorFitness[posicionFitnessAleatoria1] > vectorFitness[posicionFitnessAleatoria2])
		return posicionCromosomaAleatoria1;
	return posicionCromosomaAleatoria2;
}

//Seleccion por rango
//Se ordenan los individuos según su fitness y la selección se realiza mediante este ranking.
 int seleccionPorRangoPermutacion(int* vectorFitness, int indiceMejor, int nroPoblacion, int posActual){
	return 0;

}


//Seleccion elitista
//selecciona el mejor o segundo mejor elemento segun se indica en indiceMejor con un 1 o con un 2
 int seleccionElitistaPermutacion(int* vectorFitness, int indiceMejor, int nroPoblacion, int posActual){
	printf("*** Seleccion elitista ***\n");
	int mejor1 = -1;
	int mejor2 = -2;
	int indiceMejor1, indiceMejor2;
	int valorFitness;
	int indiceMemoria = nroPoblacion * cantCromosomasPoblacion;
	for(int i = 0; i< cantCromosomasPoblacion; i++){
		valorFitness = vectorFitness[indiceMemoria + i];
		if (valorFitness > mejor1) {
			mejor2 = mejor1;
			indiceMejor2 = indiceMejor1;
			mejor1 = valorFitness;
			indiceMejor1 = i;
		}
		else {
			if (valorFitness > mejor2){
				mejor2 = valorFitness;
				indiceMejor2 = i;
			}
		}
	}

	//printf("indiceMejor1 = %d \n", indiceMejor1);
	//printf("indiceMejor2 = %d \n", indiceMejor2);

	int posicionCromosomaMejor1 = nroPoblacion * cantCromosomasPoblacion * cantGenesEnCromosoma + indiceMejor1 * cantGenesEnCromosoma;
	int posicionCromosomaMejor2 = nroPoblacion * cantCromosomasPoblacion * cantGenesEnCromosoma + indiceMejor2 * cantGenesEnCromosoma;
	//printf("posicionCromosomaMejor1 = %d \n", posicionCromosomaMejor1);
	//printf("posicionCromosomaMejor2 = %d \n", posicionCromosomaMejor2);

	if (indiceMejor == 1) {
		return posicionCromosomaMejor1;
	}
	return posicionCromosomaMejor2;

}


/******************* Implementacion de Funciones de Cruzamiento *****************/


 void cruzamientoRepresentacionPermutacion(int* poblacionActual, int* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, int probabilidad, MersenneTwister *mt, int ejecutarFuncion, int nroPoblacion, int posActual){

	if(ejecutarFuncion == 0) {
		cruzamientoCromosomaPMX(poblacionActual, nuevaPoblacion, posicionCromosoma1, posicionCromosoma2, probabilidad, mt, nroPoblacion, posActual);
	}
	else{
		if(ejecutarFuncion == 1){
			cruzamientoCromosomaOX(poblacionActual, nuevaPoblacion, posicionCromosoma1, posicionCromosoma2, probabilidad, mt, nroPoblacion, posActual);
		}
		else {
			if(ejecutarFuncion == 2) {
				cruzamientoCromosomaCX(poblacionActual, nuevaPoblacion, posicionCromosoma1, posicionCromosoma2, probabilidad, mt, nroPoblacion, posActual);
			}
		}
	}
}

 void cruzamientoCromosomaPMX(int* poblacionActual, int* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, int probabilidad, MersenneTwister *mt, int nroPoblacion, int posActual){
	printf("*** Cruzamiento PMX ***\n");
	int posicionNuevoCromosoma1 = posActual * cantGenesEnCromosoma * 2 + nroPoblacion * totalGenesEnPoblacion;
	int posicionNuevoCromosoma2 = posicionNuevoCromosoma1 + cantGenesEnCromosoma;

	unsigned int prob;
	prob = (mt->genrand_int32() % 101);
	if(prob < probabilidad ){
		unsigned int r1 = mt->genrand_int32() % cantGenesEnCromosoma;
		unsigned int r2 = mt->genrand_int32() % cantGenesEnCromosoma;
		//printf("r1 %d\n", r1);
		//printf("r2 %d\n", r2);

		int i = 0;
		while(r2 == r1){
			r2 = (mt->genrand_int32()+1) % cantGenesEnCromosoma;
			i++;
		}

		if(r2<r1){
			unsigned int r3 = r1;
			r1 = r2;
			r2 = r3;
		}

		for(int j=0; j<cantGenesEnCromosoma; j++){
			if((j>=r1) && (j <= r2)){
				nuevaPoblacion[posicionNuevoCromosoma1+j] = poblacionActual[posicionCromosoma1+j];
				nuevaPoblacion[posicionNuevoCromosoma2+j] = poblacionActual[posicionCromosoma2+j];
			}else{
				nuevaPoblacion[posicionNuevoCromosoma1+j] = -1;
				nuevaPoblacion[posicionNuevoCromosoma2+j] = -1;
			}
		}
		int valor, valorInicial;
		for(int k=r1; k<=r2; k++){
			printf("k %d\n", k);
			valor = poblacionActual[posicionCromosoma2+k];
			valorInicial = valor;
			int pos = dondeEsta(poblacionActual,valor,posicionCromosoma1);

			if ((pos<r1) || (pos>r2)) {
				valor = poblacionActual[posicionCromosoma1+pos];
				pos = dondeEsta(poblacionActual,valor,posicionCromosoma2);
				printf("valor %d pos %d\n", valor, pos);
				while ((pos>=r1) && (pos<=r2)) {
					valor = poblacionActual[posicionCromosoma1+pos];
					pos = dondeEsta(poblacionActual,valor,posicionCromosoma2);
				}
				nuevaPoblacion[posicionNuevoCromosoma1+pos] = valorInicial;
			}
		}
		for(int k=r1; k<=r2; k++){
			valor = poblacionActual[posicionCromosoma1+k];
			valorInicial = valor;
			int pos = dondeEsta(poblacionActual,valor,posicionCromosoma2);
			if ((pos<r1) || (pos > r2)) {
				valor = poblacionActual[posicionCromosoma2+pos];
				pos = dondeEsta(poblacionActual,valor,posicionCromosoma1);

				while ((pos>=r1) && (pos <= r2)) {
					valor = poblacionActual[posicionCromosoma2+pos];
					pos = dondeEsta(poblacionActual,valor,posicionCromosoma1);
				}

				nuevaPoblacion[posicionNuevoCromosoma2+pos] = valorInicial;
			}
		}
		for(int i=0; i<cantGenesEnCromosoma; i++){
			if(nuevaPoblacion[posicionNuevoCromosoma1+i] == -1)
				nuevaPoblacion[posicionNuevoCromosoma1+i] = poblacionActual[posicionCromosoma2+i];
			if(nuevaPoblacion[posicionNuevoCromosoma2+i] == -1)
				nuevaPoblacion[posicionNuevoCromosoma2+i] = poblacionActual[posicionCromosoma1+i];
		}
	}
	else{
		for(int i=0; i<cantGenesEnCromosoma; i++){
			nuevaPoblacion[posicionNuevoCromosoma1+i] = poblacionActual[posicionCromosoma1 + i];
			nuevaPoblacion[posicionNuevoCromosoma2+i] = poblacionActual[posicionCromosoma2 + i];
		}
	}
}


 void cruzamientoCromosomaOX(int* poblacionActual, int* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, int probabilidad, MersenneTwister *mt, int nroPoblacion, int posActual){
	printf("*** Cruzamiento OX ***\n");
	int posicionNuevoCromosoma1 = posActual * cantGenesEnCromosoma * 2 + nroPoblacion * totalGenesEnPoblacion;
	int posicionNuevoCromosoma2 = posicionNuevoCromosoma1 + cantGenesEnCromosoma;

	unsigned int prob = (mt->genrand_int32() % 101);
	if(prob < probabilidad ){
		unsigned int r1 = mt->genrand_int32() % cantGenesEnCromosoma;
		unsigned int r2 = mt->genrand_int32() % cantGenesEnCromosoma;
		printf("r1 %d\n", r1);
		printf("r2 %d\n", r2);

		int i = 0;
		while(r2 == r1){
			r2 = (mt->genrand_int32() + 1) % cantGenesEnCromosoma;
			i++;
		}

		if(r2<r1){
			unsigned int r3 = r1;
			r1 = r2;
			r2 = r3;
		}

		for (int i=0; i<=cantGenesEnCromosoma; i++){
			nuevaPoblacion[posicionNuevoCromosoma1+i] = -1;
			nuevaPoblacion[posicionNuevoCromosoma2+i] = -1;
		}

		int cont1 = 0;
	    int cont2 = 0;
	    for (int i=r1; i<=r2; i++){
	    	nuevaPoblacion[posicionNuevoCromosoma1+i] = poblacionActual[posicionCromosoma1+i];
		    cont1++;

		    nuevaPoblacion[posicionNuevoCromosoma2+i] = poblacionActual[posicionCromosoma2+i];
		    cont2++;
	    }

	    int j = (r2+1) % cantGenesEnCromosoma;
		int k = (r2+1) % cantGenesEnCromosoma;

		while (cont1 < cantGenesEnCromosoma) {
			//if (estaPresente(poblacionActual[posicionCromosoma2 + j], nuevaPoblacion, posicionCromosoma1) == 0) {
			if (estaPresente(poblacionActual[posicionCromosoma2 + j], nuevaPoblacion, posicionCromosoma1, posicionCromosoma1 + cantGenesEnCromosoma) == 0) {
				nuevaPoblacion[posicionNuevoCromosoma1+k] = poblacionActual[posicionCromosoma2 + j];
				cont1++;
				k = (k+1) % cantGenesEnCromosoma;
			}
			j = (j+1) % cantGenesEnCromosoma;
		}

		j = (r2+1) % cantGenesEnCromosoma;
		k = (r2+1) % cantGenesEnCromosoma;
		while (cont2 < cantGenesEnCromosoma) {
			//if (estaPresente(poblacionActual[posicionCromosoma1 + j], nuevaPoblacion, posicionCromosoma2) == 0) {
			if (estaPresente(poblacionActual[posicionCromosoma1 + j], nuevaPoblacion, posicionCromosoma2, posicionCromosoma2 + cantGenesEnCromosoma) == 0) {
				nuevaPoblacion[posicionNuevoCromosoma2+k] = poblacionActual[posicionCromosoma1 + j];
				cont2++;
				k = (k+1) % cantGenesEnCromosoma;
			}
			j = (j+1) % cantGenesEnCromosoma;
		}

	}
	else{
		for(int i=0; i<cantGenesEnCromosoma; i++){
			nuevaPoblacion[posicionNuevoCromosoma1+i] = poblacionActual[posicionCromosoma1 + i];
			nuevaPoblacion[posicionNuevoCromosoma2+i] = poblacionActual[posicionCromosoma2 + i];
		}
	}
}


 void cruzamientoCromosomaCX(int* poblacionActual, int* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, int probabilidad,MersenneTwister *mt, int nroPoblacion, int posActual){
	printf("*** Cruzamiento CX ***\n");
	int posicionNuevoCromosoma1 = posActual * cantGenesEnCromosoma * 2 + nroPoblacion * totalGenesEnPoblacion;
	int posicionNuevoCromosoma2 = posicionNuevoCromosoma1 + cantGenesEnCromosoma;
	printf("posicionCromosoma1  %d\n", posicionCromosoma1);
	printf("posicionCromosoma2  %d\n", posicionCromosoma2);

	int pos, pos2;

	unsigned int prob = (mt->genrand_int32() % 101);
	if (prob < probabilidad){
		for(int i=0; i<cantGenesEnCromosoma; i++){
			nuevaPoblacion[posicionNuevoCromosoma1+i] = -1;
			nuevaPoblacion[posicionNuevoCromosoma2+i] = -1;
		}
		int cont = 0;
		pos = posicionPrimerLibre(nuevaPoblacion, posicionCromosoma1);
		while (pos != -1) {
			printf("pos  %d\n", pos);

			if (cont == 0) {
				while(nuevaPoblacion[posicionCromosoma1 + pos] == -1) {
					nuevaPoblacion[posicionCromosoma1 + pos] = poblacionActual[posicionCromosoma1 + pos];
					pos2 = dondeEsta(poblacionActual, poblacionActual[posicionCromosoma1 + pos], posicionCromosoma2);
					nuevaPoblacion[posicionCromosoma2 + pos2] = poblacionActual[posicionCromosoma1 + pos];
					pos = pos2;
					printf("pos  %d\n", pos);
				}
			}
			else {
				while(nuevaPoblacion[posicionCromosoma2 + pos] == -1) {
					nuevaPoblacion[posicionCromosoma2 + pos] = poblacionActual[posicionCromosoma1 + pos];
					pos2 = dondeEsta(poblacionActual, poblacionActual[posicionCromosoma1 + pos], posicionCromosoma2);
					nuevaPoblacion[posicionCromosoma1 + pos2] = poblacionActual[posicionCromosoma1 + pos];
					pos = pos2;
					printf("pos  %d\n", pos);
				}
			}
			cont = (cont +1) % 2;
			printf("cont  %d\n", cont);
			pos = posicionPrimerLibre(nuevaPoblacion, posicionCromosoma1);
		}
	}
	else{
		for(int i=0; i<cantGenesEnCromosoma; i++){
			nuevaPoblacion[posicionNuevoCromosoma1+i] = poblacionActual[posicionCromosoma1 + i];
			nuevaPoblacion[posicionNuevoCromosoma2+i] = poblacionActual[posicionCromosoma2 + i];
		}
	}
}



/******************* Implementacion de Funciones de Mutacion *****************/


 void mutacionPermutacion(int* poblacion, int probabilidad, MersenneTwister *mt, int ejecutarFuncion, int nroPoblacion, int posActual){

	if(ejecutarFuncion == 0) {
		mutacionPorIntercambio(poblacion, probabilidad, mt, nroPoblacion, posActual);
	}
	else {
		if(ejecutarFuncion == 1) {
			mutacionPorInsercionSimple(poblacion, probabilidad, mt, nroPoblacion, posActual);
		}
		else {
			if(ejecutarFuncion == 2) {
				mutacionPorInversionIVM(poblacion, probabilidad, mt, nroPoblacion, posActual);
			}
			else {
				if(ejecutarFuncion == 3) {
					mutacionPorMezcla(poblacion, probabilidad, mt, nroPoblacion, posActual);
				}
			}
		}
	}
}

 void mutacionPorIntercambio(int* poblacion, int probabilidad, MersenneTwister *mt, int nroPoblacion, int posActual){
	printf("*** Mutacion por intercambio ***\n");
	//unsigned int valor;
	int posicionNuevoCromosoma1 = posActual * cantGenesEnCromosoma * 2 + nroPoblacion * cantCromosomasPoblacion * cantGenesEnCromosoma;
	int posicionNuevoCromosoma2 = posicionNuevoCromosoma1 + cantGenesEnCromosoma;

	unsigned int prob = (mt->genrand_int32() % 101);
	if(prob <= probabilidad ){
		int seleccion1 = (mt->genrand_int32() % cantGenesEnCromosoma);
		int seleccion2 = ((mt->genrand_int32() + 1) % cantGenesEnCromosoma);
		printf("seleccion1  %d\n", seleccion1);
		printf("seleccion2  %d\n", seleccion2);
		int aux = poblacion[posicionNuevoCromosoma1 + seleccion1];
		poblacion[posicionNuevoCromosoma1 + seleccion1] = poblacion[posicionNuevoCromosoma1 + seleccion2];
		poblacion[posicionNuevoCromosoma1 + seleccion2] = aux;

	}
	prob = (mt->genrand_int32() % 101);
	if(prob <= probabilidad ){
		int seleccion1 = (mt->genrand_int32() % cantGenesEnCromosoma);
		int seleccion2 = ((mt->genrand_int32() + 1) % cantGenesEnCromosoma);
		printf("seleccion1  %d\n", seleccion1);
		printf("seleccion2  %d\n", seleccion2);
		int aux = poblacion[posicionNuevoCromosoma2 + seleccion1];
		poblacion[posicionNuevoCromosoma2 + seleccion1] = poblacion[posicionNuevoCromosoma2 + seleccion2];
		poblacion[posicionNuevoCromosoma2 + seleccion2] = aux;
	}
}

 void mutacionPorInsercionSimple(int* poblacion, int probabilidad, MersenneTwister *mt, int nroPoblacion, int posActual){
	printf("*** Mutacion por insercion simple ***\n");
	//unsigned int valor;
	int posicionNuevoCromosoma1 = posActual * cantGenesEnCromosoma * 2 + nroPoblacion * cantCromosomasPoblacion * cantGenesEnCromosoma;
	int posicionNuevoCromosoma2 = posicionNuevoCromosoma1 + cantGenesEnCromosoma;
	int i = 0;
	unsigned int r3;
	int aux;
	unsigned int r1, r2;

	unsigned int prob = (mt->genrand_int32() % 101);
	if(prob < probabilidad ){
		r1 = mt->genrand_int32() % cantGenesEnCromosoma;
		r2 = mt->genrand_int32() % cantGenesEnCromosoma;

		while(r2 == r1){
			r2 =(mt->genrand_int32() + i) % cantGenesEnCromosoma;
			i++;
		}

		if(r2 < r1){
			r3 = r1;
			r1 = r2;
			r2 = r3;
		}
		printf("r1  %d\n", r1);
		printf("r2  %d\n", r2);

		aux = poblacion[posicionNuevoCromosoma1+r2];
	    for (int i=r2; i>r1+1; i--){
	    	poblacion[posicionNuevoCromosoma1+i] = poblacion[posicionNuevoCromosoma1+i-1];
	    }
	    poblacion[posicionNuevoCromosoma1+r1+1] = aux;

	}

	prob = (mt->genrand_int32() % 101);
	if(prob < probabilidad ){
		r1 =(mt->genrand_int32() + 1) % cantGenesEnCromosoma;
		r2 =(mt->genrand_int32() + 1) % cantGenesEnCromosoma;

		i = 0;
		while(r2 == r1){
			r2 =(mt->genrand_int32() + i) % cantGenesEnCromosoma;
			i++;
		}

		if(r2 < r1){
			r3 = r1;
			r1 = r2;
			r2 = r3;
		}
		printf("r1  %d\n", r1);
		printf("r2  %d\n", r2);

		aux = poblacion[posicionNuevoCromosoma2+r2];
		for (int i=r2; i>r1+1; i--){
			poblacion[posicionNuevoCromosoma2+i] = poblacion[posicionNuevoCromosoma2+i-1];
		}
		poblacion[posicionNuevoCromosoma2+r1+1] = aux;

	}
}


 void mutacionPorInversionIVM(int* poblacion, int probabilidad, MersenneTwister *mt, int nroPoblacion, int posActual){
	printf("*** Mutacion por inversion IVM ***\n");
//	unsigned int valor;
	int posicionNuevoCromosoma1 = posActual * cantGenesEnCromosoma * 2 + nroPoblacion * cantCromosomasPoblacion * cantGenesEnCromosoma;
	int posicionNuevoCromosoma2 = posicionNuevoCromosoma1 + cantGenesEnCromosoma;
	int i = 0;
	unsigned int r3;
	//int aux;
	unsigned int r1, r2;
	//int tamArreglo;
	int tam, tam2, j;

	unsigned int prob = (mt->genrand_int32() % 101);
	if(prob < probabilidad ){
		r1 = mt->genrand_int32() % cantGenesEnCromosoma;
		r2 = mt->genrand_int32() % cantGenesEnCromosoma;

		while(r2 == r1){
			r2 =(mt->genrand_int32() + i) % cantGenesEnCromosoma;
			i++;
		}

		if(r2 < r1){
			r3 = r1;
			r1 = r2;
			r2 = r3;
		}

		printf("r1  %d\n", r1);
		printf("r2  %d\n", r2);
		tam = r2-r1+1;
		tam2 = r2;
		//tamArreglo = (tam)*sizeof(int);
		int arregloAux[20];

		for (int i=0; i<tam; i++){
			arregloAux[i] = poblacion[posicionNuevoCromosoma1+tam2];
			tam2--;
			printf("%d", arregloAux[i]);
			printf("-");
		}

		j = 0;
		for (int i=r1; i<=r2; i++){
			poblacion[posicionNuevoCromosoma1+i] = arregloAux[j];
			j++;
		}
	}

	prob = (mt->genrand_int32() % 101);
	if(prob < probabilidad ){
		r1 =(mt->genrand_int32() + 1) % cantGenesEnCromosoma;
		r2 =(mt->genrand_int32() + 1) % cantGenesEnCromosoma;

		i = 0;
		while(r2 == r1){
			r2 =(mt->genrand_int32() + i) % cantGenesEnCromosoma;
			i++;
		}

		if(r2 < r1){
			r3 = r1;
			r1 = r2;
			r2 = r3;
		}

		printf("r1  %d\n", r1);
		printf("r2  %d\n", r2);

		tam = r2-r1+1;
		tam2 = r2;
		//tamArreglo = (tam)*sizeof(int);
		int arregloAux2[20];

		for (int i=0; i<tam; i++){
			arregloAux2[i] = poblacion[posicionNuevoCromosoma2+tam2];
			tam2--;
			printf("%d", arregloAux2[i]);
			printf("-");
		}
		j = 0;
		for (int i=r1; i<=r2; i++){
			poblacion[posicionNuevoCromosoma2+i] = arregloAux2[j];
			j++;
		}
	}
}


 void mutacionPorMezcla(int* poblacion, int probabilidad, MersenneTwister *mt, int nroPoblacion, int posActual){
	printf("*** Mutacion por mezcla ***\n");
	int posicionNuevoCromosoma1 = posActual * cantGenesEnCromosoma * 2 + nroPoblacion * cantCromosomasPoblacion * cantGenesEnCromosoma;
	int posicionNuevoCromosoma2 = posicionNuevoCromosoma1 + cantGenesEnCromosoma;

	//Esto va a ser un numero aleatorio hay que cambiarlo cuando sepamos como hacer arreglos dinamicos en CUDA!!!!
	int cantMezclados = 4;
	int arregloPosiciones[4];
	int arregloValores[4];
	int arregloPosicionesMezcladas[4];
	unsigned int r;
	unsigned int prob = (mt->genrand_int32() % 101);
	if (prob < probabilidad ){
		for (int i = 0; i<cantMezclados; i++){
			r = (mt->genrand_int32()% cantGenesEnCromosoma);
			while(estaPresente(r, arregloPosiciones, 0, i)){
				r = (r+1) % cantGenesEnCromosoma;
			}
			arregloPosiciones[i] = r;
		}

		for (int i = 0; i<cantMezclados; i++){
			r = (mt->genrand_int32()% cantMezclados);
			while(estaPresente(arregloPosiciones[r], arregloPosicionesMezcladas, 0, i)){
				r = (r+1) % cantMezclados;
			}
			arregloPosicionesMezcladas[i] = arregloPosiciones[r];
			arregloValores[i] = poblacion[posicionNuevoCromosoma1+arregloPosiciones[r]];
		}

		for (int i = 0; i<cantMezclados; i++){
			poblacion[posicionNuevoCromosoma1 + arregloPosiciones[i]] = arregloValores[i];
		}
	}

	prob = (mt->genrand_int32() % 101);
	if (prob < probabilidad ){
		for (int i = 0; i<cantMezclados; i++){
			r = (mt->genrand_int32()% cantGenesEnCromosoma);
			while(estaPresente(r, arregloPosiciones, 0, i)){
				r = (r+1) % cantGenesEnCromosoma;
			}
			arregloPosiciones[i] = r;
		}

		for (int i = 0; i<cantMezclados; i++){
			r = (mt->genrand_int32()% cantMezclados);
			while(estaPresente(arregloPosiciones[r], arregloPosicionesMezcladas, 0, i)){
				r = (r+1) % cantMezclados;
			}
			arregloPosicionesMezcladas[i] = arregloPosiciones[r];
			arregloValores[i] = poblacion[posicionNuevoCromosoma2+arregloPosiciones[r]];
		}

		for (int i = 0; i<cantMezclados; i++){
			poblacion[posicionNuevoCromosoma2 + arregloPosiciones[i]] = arregloValores[i];
		}
	}


	printf("\nPosiciones\n");
	for (int i =0; i<4;i++) {
	  printf("%d ",arregloPosiciones[i]);
	}

	printf("\nPosiciones Mezcladas\n");
	for (int i =0; i<4;i++) {
	  printf("%d ",arregloPosicionesMezcladas[i]);
	}

	printf("\nValores\n");
	for (int i =0; i<4;i++) {
	  printf("%d ",arregloValores[i]);
	}

}

/******************* Implementacion de Funciones de fitness *****************/

 void asignarFitnessPermutacion(int* nuevaPoblacion, int* nuevoVectorFitness, int nroPoblacion, int posActual){
	//Obtengo posicion del primer cromosoma.
	int posicionCromosoma = posActual * cantGenesEnCromosoma * 2 + nroPoblacion * totalGenesEnPoblacion;
	int posicionFitness = posActual * 2 + nroPoblacion * cantCromosomasPoblacion;
	nuevoVectorFitness[posicionFitness] = calcularFitnessPermutacion(nuevaPoblacion, posicionCromosoma);
	nuevoVectorFitness[posicionFitness + 1] = calcularFitnessPermutacion(nuevaPoblacion, posicionCromosoma + cantGenesEnCromosoma);
}

 int calcularFitnessPermutacion(int* poblacion, int posicion) {
	int fitness = 0;
	float contador = cantGenesEnCromosoma-1;
	for(int i=0; i<cantGenesEnCromosoma; i++){
	  fitness = fitness + poblacion[posicion + i];
	  contador--;
	}
	return fitness;
}


/******************* Implementacion de Funciones del host *****************/

void representacionPermutacion() {

	int tamVectorPoblacion = sizeof(int)*totalGenes;
	int tamVectorFitness = sizeof(int)*totalIndividuos;
	int tamVectorIndividuosAMigrar = sizeof(int)*cantGenesEnCromosoma*cantidadPoblaciones;

	static int *poblacionActualHost = (int *) malloc(tamVectorPoblacion);
	static int *nuevaPoblacionHost = (int *) malloc(tamVectorPoblacion);
	static int *fitnessActualHost = (int *) malloc(tamVectorFitness);
	static int *nuevoFitnessHost = (int *) malloc(tamVectorFitness);
	static int *individuosAMigrarHost = (int *) malloc(tamVectorIndividuosAMigrar);

	//inicializo la clase mt para las variables aleatorias
	MersenneTwister* mt;

	//Inicio numeros aleatorios.
	mt = new MersenneTwister();
	mt->init_genrand(time(NULL));

	//inicializacion de la poblacion en GPU
	inicializarPoblacionPermutacion(poblacionActualHost, fitnessActualHost, mt, cantCromosomasPoblacion);

	cout << "\nPOBLACION INICIAL\n";
	for (int i = 0; i<totalGenes; i++){
		if(i%cantGenesEnCromosoma == 0){
			cout << "\n";

		}
		printf("%i ", poblacionActualHost[i]);
	}
	cout << "\n\n\nFITNESS\n";

	for (int i = 0; i<cantCromosomasPoblacion * cantidadPoblaciones; i++){
		printf("%i ", fitnessActualHost[i]);
	}
	cout << "\n\n\n\n";

	int nroPoblacion;
	int iteracion = 0;
	//los individuos de la poblacion actual se van intercambiando en el reemplazo
	while(iteracion < numeroGeneraciones){
		nroPoblacion = 0;
		for (int i = 0; i < cantidadPoblaciones*cantCromosomasPoblacion/2; i++){
			nroPoblacion = i/(cantCromosomasPoblacion/2);
			//si la iteracion es par invoco a GPU con poblacionActual, nuevaPoblacion
			if ((iteracion % 2) == 0) {
				// seleccionamos, cruzamos y mutamos en GPU
				mainKernelPermutacion(poblacionActualHost, nuevaPoblacionHost, fitnessActualHost, nuevoFitnessHost, individuosAMigrarHost, mt, nroPoblacion, i%(cantCromosomasPoblacion/2));

				//Si hay que migrar
				//if (iteracion % generacionesMigrar == 0) {
				//	migracionRepresentacion<<<tamGrid, tamBlockMigracion>>>(nuevaPoblacion, nuevoFitness, individuosAMigrar, r);
				//}
			}
			//sino invoco a GPU con nuevaPoblacion, poblacionActual
			else {

				// seleccionamos, cruzamos y mutamos en GPU
				mainKernelPermutacion(nuevaPoblacionHost, poblacionActualHost, nuevoFitnessHost, fitnessActualHost, individuosAMigrarHost, mt, nroPoblacion,  i%(cantCromosomasPoblacion/2));

				//Si hay que migrar
				//if (iteracion % generacionesMigrar == 0) {
				//	migracionRepresentacion<<<tamGrid, tamBlockMigracion>>>(poblacionActual, fitnessActual, individuosAMigrar, r);
				//}
			}
		}

		//mejorFitness = obtenerMejorFitness(poblacionActual,mejorCromosoma);
		iteracion++;
	}

	cout << "NUEVA POBLACION\n";
	for (int i = 0; i<totalGenes; i++){
		if(i%cantGenesEnCromosoma == 0){
			cout << "\n";

		}
		printf("%i ", nuevaPoblacionHost[i]);
	}
	cout << "\n\n\nFITNESS\n";

	for (int i = 0; i<cantCromosomasPoblacion * cantidadPoblaciones; i++){
		printf("%i ", nuevoFitnessHost[i]);
	}
	cout << "\n";

/*	cout << "\n\nA MIGRAR\n";

	for (int i = 0; i<cantGenesEnCromosoma * cantidadPoblaciones; i++){
		if(i%cantGenesEnCromosoma == 0){
			cout << "\n";
		}
		printf("%i ", individuosAMigrarHost[i]);
	}
	cout << "\n";
*/
}
